package controller;

import java.util.HashMap;
import java.util.Map;

import model.Afd;
import model.State;
import model.Transition;

public class KleeneController {
	private Map<Integer, Map<Integer, Map<Integer, StringBuilder>>> table;
	private Afd afd;

	private static KleeneController kleeneController;

	private KleeneController() {
		table = new HashMap<Integer, Map<Integer, Map<Integer, StringBuilder>>>();
	}

	public static KleeneController getInstance() {
		if (kleeneController == null) {
			kleeneController = new KleeneController();
		}
		return kleeneController;
	}

	public String kleene() {
		afd = AfdController.getInstance().getAfd();

		initTable();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < afd.getStates().size(); i++) {
			for (int j = 0; j < afd.getStates().size(); j++) {
				for (int k = 0; k <= afd.getStates().size(); k++) {
					calcKleene(i, j, k);
				}
			}
		}
		getResponse(sb);
		
		return sb.toString();
	}

	private void initTable() {
		for (int i = 0; i < afd.getStates().size(); i++) {
			table.put(i, new HashMap<Integer, Map<Integer, StringBuilder>>());
			for (int j = 0; j < afd.getStates().size(); j++) {
				table.get(i).put(j, new HashMap<Integer, StringBuilder>());
			}
		}
	}

	void getResponse(StringBuilder sb) {
		int count = 0;
		State statej;
		for (int j = 0; count < afd.getFinalStates().size() ; j++) {
			statej = afd.getStates().get(j);
			if (afd.getFinalStates().contains(statej)) {
				sb.append("(");
				sb.append(table.get(0).get(j).get(afd.getStates().size())).append(")");
				sb.append("U");
				count++;
			}
		}
		if(sb.toString().length() > 0)
			sb.deleteCharAt(sb.toString().length() - 1);
	}

	private String calcKleene(int i, int j, int k) {
		StringBuilder response = table.get(i).get(j).get(k);
		if (response == null) {
			State statei = afd.getStates().get(i);
			State statej = afd.getStates().get(j);

			response = new StringBuilder();
			if (k == 0) {
				calcBase(statei, statej, response);
			} else {
				response.append(calcKleene(i, j, k - 1)).append("U").append("(");
				response.append(calcKleene(i, k-1, k - 1));
				response.append("(").append(calcKleene(k-1, k-1, k - 1)).append(")").append("*");
				response.append(calcKleene(k-1, j, k - 1)).append(")");
			}
			table.get(i).get(j).put(k, response);
		}
		return response.toString();
	}

	void calcBase(State statei, State statej, StringBuilder response) {
		if(statei.equals(statej)){
			response.append("ɛU");
		}
		for (Transition t : afd.getTransitions()) {
			if (t.getInitialState().equals(statei)
					&& t.getFinalState().equals(statej)) {
				response.append(t.getSymbol()).append("U");
			}
		}
		if (response.toString().length() > 0) {
			response.deleteCharAt(response.toString().length() - 1);
		}
	}
}
